package com.theeviljames.lexer;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import com.theeviljames.syntax.Rule;

public class PGrammar {

	private static Hashtable<String, Hashtable<String,Integer>> precedenceTable;
	private static Hashtable<Integer, Rule> grammar;
	private static Token startingSymbol;
	
	static{
		precedenceTable = new Hashtable<String, Hashtable<String,Integer>>();
		grammar = new Hashtable<Integer, Rule>();
		try{
			BufferedReader br = new BufferedReader(new FileReader("lib/grammar.bnf"));
			String s = br.readLine();
			int i = 0;
			while(s!=null){
				if(s.substring(0, 1).equals("#")){
					s = br.readLine();
					continue;
				}
				StringTokenizer st = new StringTokenizer(s,"@");
				String[] rhs = new String[st.countTokens()-2];
				String lhs = st.nextToken().replaceAll("<", "").replaceAll(">", "").replaceAll("\"", "");
				st.nextToken();
				int j = 0;
				while(true){
					if(st.countTokens()==0)break;
					rhs[j++] = st.nextToken().replaceAll("<", "").replaceAll(">", "").replaceAll("\"", "");
				}
				Rule rule = new Rule(lhs,rhs);
				grammar.put(i++, rule);
				s = br.readLine();
			}
			for(Enumeration<Integer> e = grammar.keys(); e.hasMoreElements();){
				i = e.nextElement();				
				System.out.println(""+ i + ">" +grammar.get(i));
			}
			
			Hashtable<String, Integer> E = new Hashtable<String, Integer>();
			E.put(")", 0);
			precedenceTable.put("E", E);
			startingSymbol = new Token("E",Token.NONTERMINAL);
			
			Hashtable<String, Integer> Eq = new Hashtable<String, Integer>();
			Eq.put("A", 0);
			Eq.put("==", 0);
			Eq.put("!=", 0);
			Eq.put(")", 1);
			precedenceTable.put("EQ", Eq);
			
			Hashtable<String, Integer> A = new Hashtable<String, Integer>();
			A.put(")", 1);
			A.put("==", 1);
			A.put("!=", 1);
			A.put("+", 1);
			A.put("-", 1);
			precedenceTable.put("A", A);
			
			Hashtable<String, Integer> equalsequals = new Hashtable<String, Integer>();
			equalsequals.put("A", 0);
			equalsequals.put("M", -1);
			equalsequals.put("-", -1);
			equalsequals.put("P", -1);
			equalsequals.put("(", -1);
			equalsequals.put("CONSTANT", -1);
			equalsequals.put("IDENTIFIER", -1);
			precedenceTable.put("==", equalsequals);
			
			Hashtable<String, Integer> notequals = new Hashtable<String, Integer>();
			notequals.put("A", 0);
			notequals.put("M", -1);
			notequals.put("-", -1);
			notequals.put("P", -1);
			notequals.put("(", -1);
			notequals.put("CONSTANT", -1);
			notequals.put("IDENTIFIER", -1);
			precedenceTable.put("!=", notequals);
			
			Hashtable<String, Integer> M = new Hashtable<String, Integer>();
			M.put("A", 0);
			M.put("==", 1);
			M.put("!=", 1);
			M.put("+", 0);
			M.put("-", 0);
			M.put(")", 1);
			precedenceTable.put("M", M);
			
			Hashtable<String, Integer> plus = new Hashtable<String, Integer>();
			plus.put("A", 0);
			plus.put("M", -1);
			plus.put("-", -1);
			plus.put("P", -1);
			plus.put("(", -1);
			plus.put("CONSTANT", -1);
			plus.put("IDENTIFIER", -1);
			precedenceTable.put("+", plus);
			
			Hashtable<String, Integer> minus = new Hashtable<String, Integer>();
			minus.put("A", 0);
			minus.put("M", -1);
			minus.put("-", -1);
			minus.put("P", -1);
			minus.put("(", -1);
			minus.put("CONSTANT", -1);
			minus.put("IDENTIFIER", -1);
			precedenceTable.put("-", minus);
			
			Hashtable<String, Integer> P = new Hashtable<String, Integer>();
			P.put("==", 1);
			P.put("!=", 1);
			P.put("+", 1);
			P.put("-", 1);
			P.put("P", 0);
			P.put("^", 0);
			P.put("*", 0);
			P.put("/", 0);
			P.put(")", 1);
			precedenceTable.put("P", P);
			
			Hashtable<String, Integer> hat = new Hashtable<String, Integer>();
			hat.put("-", -1);
			hat.put("P", 0);
			hat.put("(", -1);
			hat.put("CONSTANT", -1);
			hat.put("IDENTIFIER", -1);
			precedenceTable.put("^", hat);
			
			Hashtable<String, Integer> star = new Hashtable<String, Integer>();
			star.put("-", -1);
			star.put("P", 0);
			star.put("(", -1);
			star.put("CONSTANT", -1);
			star.put("IDENTIFIER", -1);
			precedenceTable.put("*", star);
			
			Hashtable<String, Integer> div = new Hashtable<String, Integer>();
			div.put("-", -1);
			div.put("P", 0);
			div.put("(", -1);
			div.put("CONSTANT", -1);
			div.put("IDENTIFIER", -1);
			precedenceTable.put("/", div);
			
			Hashtable<String, Integer> lparen = new Hashtable<String, Integer>();
			lparen.put("E", 0);
			lparen.put("EQ", -1);
			lparen.put("A", -1);
			lparen.put("M", -1);
			lparen.put("-", -1);
			lparen.put("P", -1);
			lparen.put("(", -1);
			lparen.put(")", 0);
			lparen.put("CONSTANT", -1);
			lparen.put("IDENTIFIER", -1);
			precedenceTable.put("(", lparen);
			
			Hashtable<String, Integer> rparen = new Hashtable<String, Integer>();
			rparen.put("==", 1);
			rparen.put("!=", 1);
			rparen.put("+", 1);
			rparen.put("-", 1);
			rparen.put("^", 1);
			rparen.put("*", 1);
			rparen.put("/", 1);
			rparen.put(")", 1);
			precedenceTable.put(")", rparen);
			
			Hashtable<String, Integer> constant = new Hashtable<String, Integer>();
			constant.put("==", 1);
			constant.put("!=", 1);
			constant.put("+", 1);
			constant.put("-", 1);
			constant.put("^", 1);
			constant.put("*", 1);
			constant.put("/", 1);
			constant.put(")", 1);
			precedenceTable.put("CONSTANT", constant);
			
			Hashtable<String, Integer> identifier = new Hashtable<String, Integer>();
			identifier.put("==", 1);
			identifier.put("!=", 1);
			identifier.put("+", 1);
			identifier.put("-", 1);
			identifier.put("^", 1);
			identifier.put("*", 1);
			identifier.put("/", 1);
			identifier.put(")", 1);
			precedenceTable.put("IDENTIFIER", identifier);
			
			
			
			
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
	}
	
	public static Token getStartingSymbol(){
		return startingSymbol;
	}
	public static Token matchRHS(ArrayList<Token> rhs){
		String[] rhsTokens = new String[rhs.size()];
		int counter = 0;
		for(Token t:rhs)rhsTokens[counter++]=getGrammarString(t);
		for(Enumeration e = grammar.keys(); e.hasMoreElements();){
			Rule rule = grammar.get(e.nextElement());
			String[] currentRHS = rule.getRhs();
			if(rhsTokens.length==currentRHS.length){
				int i = 0;
				for(; i < rhsTokens.length; i++){
					//System.out.println("Token array[" + i + "]>" + rhsTokens[i]);
					//System.out.println("Rule array[" + i + "]>" + currentRHS[i]);
					
					if(!rhsTokens[i].equals(currentRHS[i])){
						//System.out.println("Not equals from 217 in PGrammar");
						break;
					}
				}
				if(i==(rhsTokens.length)){
					System.out.println("Returning a non-terminal>" +rule.getLhs());
					return new Token(""+rule.getLhs(),Token.NONTERMINAL);
				}
			}
		}
		return null;
	}
	
	public PGrammar() {
		// TODO Auto-generated constructor stub
	}
	
	public static final int precedence(Token a, Token b){
		String c = getGrammarString(a);
		String d = getGrammarString(b);
		if(!precedenceTable.get(c).containsKey(d)){
			System.out.println();
			return -2;
		}
		return precedenceTable.get(c).get(d);
	}
	
	public static String getGrammarString(Token a){
		if(a.getType()==Token.CONSTANT)return "CONSTANT";
		if(a.getType()==Token.IDENTIFIER)return "IDENTIFIER";
		return a.getLiteral();
		
	}
	
	public static void main(String[] args) {
		PGrammar pg = new PGrammar();
	}
}
